using System;

namespace DeflateLib
{
    /// <summary>
    /// Infinite circle buffer to store data. Saves only limited amount of data.
    /// </summary>
	sealed class InfiniteBuffer
	{	
		byte[] buffer;
		int bufferSize;
		int position;
		long realPosition;
	
		internal int BufferSize
		{
			get { return bufferSize; }
		}

        internal long RealPosition
        {
            get { return realPosition; }
        }
		
		internal long Lost
		{
			get
			{
				return realPosition > BufferSize ? realPosition - BufferSize : 0;
			}
		}
	
		internal InfiniteBuffer(int bufferSize)
		{
			this.bufferSize = bufferSize;
			this.buffer = new byte[bufferSize];
			this.position = 0;
			this.realPosition = 0;
		}
		
        internal void WriteByte(byte b)
        {
			buffer[position++] = b;
			if (position >= BufferSize) position = 0;
			realPosition++;
        }		
        
		internal void Write(byte[] data, int offset, int length)
		{
			realPosition += length;
		
			if(length >= bufferSize)
			{
				Array.Copy(data, offset, buffer, 0, BufferSize);
				position = 0;
			}
			else if (position + length > BufferSize)
			{
				int headLength = BufferSize - position;
				int tailLength = position + length - BufferSize;
				Array.Copy(data, offset, buffer, position, headLength);
				Array.Copy(data, offset + headLength, buffer, 0, tailLength);
				position = tailLength;
			}
			else
			{
				Array.Copy(data, offset, buffer, position, length);
				position += length;
				if (position == BufferSize) position = 0;
			}
		}
		
		internal byte[] GetData(int offset, int length)
        {
            byte[] copy = new byte[length];
            if (position >= offset)
            {
                Array.Copy(buffer, position - offset, copy, 0, length);
            }
            else
            {
                int headLength = offset - position;
                if (headLength < length)
                {
                    Array.Copy(buffer, BufferSize - headLength, copy, 0, headLength);
                    Array.Copy(buffer, 0, copy, headLength, length - headLength);
                }
                else
                {
                    Array.Copy(buffer, BufferSize - headLength, copy, 0, length);
                }
            }
            return copy;		
		}		
	}
}